package checksum.test;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.zip.Adler32;
import java.util.zip.CRC32;

import common.test.Module;
import common.test.VersionNumber;

public class SumAndUpdate{
	public static void main(String[] args){
		System.out.println(args.length);
		for(int i = 0; i < args.length; i++){
			System.out.println(args[i]);
		}
		String propertyFile = "";
		String updateRevision = "";
		if(args.length == 1)
			propertyFile = args[0];
			
		if(args.length == 2){
			propertyFile = args[0];
			updateRevision = args[1];
		}
		
		try{
			System.out.println("Updating checksums...");

			InputStream stream = new FileInputStream(propertyFile);
			Properties properties = new Properties();
			properties.load(stream);
			stream.close();

			Collection<Object> collection = properties.values();
			Iterator<Object> i = collection.iterator();

			String version;
			String[] splitString;
			Module module = null;
			while(i.hasNext()){
				version = (String) i.next();
				splitString = version.split("[|]");
				String moduleFilename = splitString[1].trim();
				String moduleName = moduleFilename.substring(0, moduleFilename.lastIndexOf("."));
				if(splitString.length == 2)
					module = new Module(moduleName, new VersionNumber(splitString[0].trim()), moduleFilename);
				else if(splitString.length == 3)
					module = new Module(moduleName, new VersionNumber(splitString[0].trim()), moduleFilename, splitString[2].trim());
				else if(splitString.length == 4){
					module = new Module(moduleName, new VersionNumber(splitString[0].trim()), moduleFilename, splitString[2].trim());
					String[] splitStrCS = splitString[3].trim().split(":");
					module.setChecksumType(splitStrCS[0].trim());
					module.setChecksumValue(splitStrCS[1].trim());
				}else{
					System.out.println("invalid version split: " + splitString.length);
					continue;
				}

				boolean goodCheck = false;
				while(!goodCheck){
					// Get filename of file or directory
					String filename = module.getModuleFilename();
					System.out.println(filename);
					String checksum1 = calculateChecksum(filename, "SHA1");
					String checksum2 = calculateChecksum(filename, "SHA1");
					if(checksum1.equals(checksum2)){
						module.setChecksumType("SHA1");
						module.setChecksumValue(checksum1);
						if(updateRevision.length() > 0){
							System.out.println("Updating Revision: " + updateRevision);
							module.incrementVersion(updateRevision);
						}
						properties.put(module.getModuleName(), module.toString());
						goodCheck = true;
					}
				}
			}
			
			FileOutputStream propsOut = new FileOutputStream(propertyFile);
			properties.store(propsOut, "---Checksum Update---");
			propsOut.close();
			
		}catch(NoSuchAlgorithmException e){
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch(IOException e){
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private static String calculateChecksum(String filename, String sumType) throws IOException, NoSuchAlgorithmException{
		// start timing
		// long startMillis = System.currentTimeMillis();
		long timeAdler32 = 0L;
		long timeCRC32 = 0L;
		long timeMD5 = 0L;
		long timeSHA1 = 0L;
		long timeWrite = 0L;
		// long timeCalc = 0L;
		long timeRead = 0L;
		long start = 0L;
		// long startDload = 0L;
		// long currentDuration;
		// long sDur = startMillis;
		// long eDur;
		// long dur;
		// int startBytes = 0;

		File file = new File(filename);

		InputStream inStream = new FileInputStream(file);
		DataInputStream dis = new DataInputStream(new BufferedInputStream(inStream));
		// DataOutputStream dos = new DataOutputStream(new
		// BufferedOutputStream(new FileOutputStream(module.getModuleFilename()
		// + ".upd")));

		// DLoadProgress dlp = new DLoadProgress();

		MessageDigest checksumMD5 = MessageDigest.getInstance("MD5");
		MessageDigest checksumSHA1 = MessageDigest.getInstance("SHA-1");
		Adler32 checksumAdler32 = new Adler32();
		CRC32 checksumCRC32 = new CRC32();
		int bytesRead = 0;
		int totalBytes = 0;
		byte data[] = new byte[1024];
		start = System.currentTimeMillis();
		// startDload = start;
		// int prevProgress = 0;
		while((bytesRead = dis.read(data)) > -1){
			totalBytes += bytesRead;
			timeRead += (System.currentTimeMillis() - start);

			start = System.currentTimeMillis();
			// dos.write(data, 0, bytesRead);
			timeWrite += (System.currentTimeMillis() - start);
			start = System.currentTimeMillis();
			checksumAdler32.update(data, 0, bytesRead);
			timeAdler32 += (System.currentTimeMillis() - start);
			start = System.currentTimeMillis();
			checksumCRC32.update(data, 0, bytesRead);
			timeCRC32 += (System.currentTimeMillis() - start);
			start = System.currentTimeMillis();
			checksumMD5.update(data, 0, bytesRead);
			timeMD5 += (System.currentTimeMillis() - start);
			start = System.currentTimeMillis();
			checksumSHA1.update(data, 0, bytesRead);
			timeSHA1 += (System.currentTimeMillis() - start);
			//
			// start = System.currentTimeMillis();
			// int progress = Math.round((100f * totalBytes) / fileSize) / 2;
			//
			// currentDuration = System.currentTimeMillis() - startMillis + 1;
			// double averageSpeed = 1 * totalBytes / currentDuration;
			//
			// eDur = System.currentTimeMillis();
			// dur = eDur - sDur + 1;
			// double currentSpeed = 1 * (totalBytes - startBytes) / dur;
			// if(dur >= 5000d){
			// sDur += (dur / 2);
			// startBytes += ((totalBytes - startBytes) / 2);
			// }
			// dlp.setCurrentSpeed(currentSpeed);
			// dlp.setAverageSpeed(averageSpeed);
			// dlp.setProgress(progress);
			//
			// while(progress > prevProgress){
			// System.out.print(".");
			// prevProgress++;
			// }
			//
			// // System.out.println(totalBytes);
			// // System.out.println(progress);
			// // if(bytesRead == 0)
			// // System.out.println(bytesRead);
			//
			// timeCalc += (System.currentTimeMillis() - start);

			start = System.currentTimeMillis();
		}
		// System.out.println();
		// properties.setProperty(module.getModuleName(), module.toString());

		start = System.currentTimeMillis();
		String resultMD5 = "";
		data = checksumMD5.digest();
		for(int i = 0; i < data.length; i++){
			resultMD5 += Integer.toString((data[i] & 0xff) + 0x100, 16).substring(1);
		}
		timeMD5 += (System.currentTimeMillis() - start);

		start = System.currentTimeMillis();
		String resultSHA1 = "";
		data = checksumSHA1.digest();
		for(int i = 0; i < data.length; i++){
			resultSHA1 += Integer.toString((data[i] & 0xff) + 0x100, 16).substring(1);
		}
		timeSHA1 += (System.currentTimeMillis() - start);

		// System.out.println("Bytes:\t\t" + totalBytes);
		// System.out.println("Adler32:\t" + timeAdler32 + "ms\t" +
		// checksumAdler32.getValue());
		// System.out.println("CRC32:\t\t" + timeCRC32 + "ms\t" +
		// checksumCRC32.getValue());
		// System.out.println("MD5:\t\t" + timeMD5 + "ms\t" + resultMD5);
		// System.out.println("SHA1:\t\t" + timeSHA1 + "ms\t" + resultSHA1);
		// System.out.println("Read:\t\t" + timeRead + "ms\t");
		// System.out.println("Write:\t\t" + timeWrite + "ms\t");
		// System.out.println("Calc:\t\t" + timeCalc + "ms\t");
		// long waste = (System.currentTimeMillis() - startDload) - (timeAdler32
		// + timeCRC32 + timeMD5 + timeSHA1 + timeRead + timeWrite + timeCalc);
		// System.out.println("Waste:\t\t" + waste + "ms\t");

		// StringBuffer checksumStrBuf = new StringBuffer();
		// checksumStrBuf.append("File:\t\t" + filename + "\r\n");
		// checksumStrBuf.append("Adler32:\t" + checksumAdler32.getValue() +
		// "\r\n");
		// checksumStrBuf.append("CRC32:\t\t" + checksumCRC32.getValue() +
		// "\r\n");
		// checksumStrBuf.append("MD5:\t\t" + resultMD5 + "\r\n");
		// checksumStrBuf.append("SHA1:\t\t" + resultSHA1 + "\r\n");
		// checksumStrBuf.append("\r\n");

		// dos.flush();
		// dos.close();
		dis.close();

		// End timing
		// System.out.println((System.currentTimeMillis() - startMillis) +
		// "ms");

		if(sumType.equals("Adler32"))
			return Long.toString(checksumAdler32.getValue());
		else if(sumType.equals("CRC32"))
			return Long.toString(checksumCRC32.getValue());
		else if(sumType.equals("MD5"))
			return resultMD5;
		else if(sumType.equals("SHA1"))
			return resultSHA1;
		else
			return "";
	}
}
